/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package com.plian.system.service.qg.guarantee.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.plian.Tools.*;
import com.plian.Tools.pagedata.PageData;
import com.plian.system.cache.UserCache;
import com.plian.system.common.status.CheckStatus;
import com.plian.system.constant.sys.FormStatusConstant;
import com.plian.system.constant.sys.FormTypeConstant;
import com.plian.system.constant.yth.YthConstant;
import com.plian.system.entity.qg.guarantee.PropertyGuaranteeApply;
import com.plian.system.entity.qg.guarantee.PropertyGuaranteeExecute;
import com.plian.system.entity.qg.guarantee.PropertyGuaranteeRepayment;
import com.plian.system.entity.sys.ApprovalMessage;
import com.plian.system.mapper.qg.guarantee.PropertyGuaranteeRepaymentMapper;
import com.plian.system.mybatis.base.BaseFlowService;
import com.plian.system.mybatis.base.BaseServiceImpl;
import com.plian.system.service.qg.guarantee.IPropertyGuaranteeApplyService;
import com.plian.system.service.qg.guarantee.IPropertyGuaranteeExecuteService;
import com.plian.system.service.qg.guarantee.IPropertyGuaranteeRepaymentService;
import com.plian.system.service.sys.code.IFormCodeService;
import com.plian.system.service.sys.message.IApprovalMessageService;
import com.plian.system.service.sys.orgzation.IOrgService;
import com.plian.system.service.wf.FormWorkflowService;
import com.plian.system.vo.qg.guarantee.PropertyGuaranteeRepaymentVO;
import com.plian.system.vo.yth.YthResult;
import com.plian.system.wrapper.qg.guarantee.PropertyGuaranteeRepaymentWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.plian.system.constant.sys.ApprovalMessageTypeConstant.GZW_TYPE;
import static com.plian.system.constant.sys.FormStatusConstant.UNREVIEWED;

/**
 * 企业担保执行主表 服务实现类
 *
 * @author jianglei
 * @since 2019-10-24
 */
@Slf4j
@Service
@AllArgsConstructor
public class PropertyGuaranteeRepaymentServiceImpl extends BaseServiceImpl<PropertyGuaranteeRepaymentMapper, PropertyGuaranteeRepayment> implements IPropertyGuaranteeRepaymentService, BaseFlowService {

	private IFormCodeService formCodeService;

	private IPropertyGuaranteeApplyService propertyGuaranteeApplyService;

	private IPropertyGuaranteeExecuteService propertyGuaranteeExecuteService;

	private FormWorkflowService formWorkflowService;

	private PropertyGuaranteeRepaymentWrapper propertyGuaranteeRepaymentWrapper;

	private IOrgService orgService;

	private IApprovalMessageService approvalMessageService;

	@Override
    public boolean saveOrUpdate(PropertyGuaranteeRepayment propertyGuaranteeRepayment) {
		if (!Optional.ofNullable(propertyGuaranteeRepayment.getId()).isPresent()){
			propertyGuaranteeRepayment.setCode(formCodeService.getCode(FormTypeConstant.QG_GUARANTEE_REPAYMENT_FORM));
			propertyGuaranteeRepayment.setFormType(String.valueOf(FormTypeConstant.QG_GUARANTEE_REPAYMENT_FORM));
		}
		if (!Optional.ofNullable(propertyGuaranteeRepayment.getStatus()).isPresent()) {
			propertyGuaranteeRepayment.setStatus(FormStatusConstant.UNREVIEWED);
		}

		return super.saveOrUpdate(propertyGuaranteeRepayment);
    }

	/**
	 * 删除只考虑
	 * @param ids id集合(逗号分隔)
	 * @return
	 */
	@Override
    public boolean deleteLogic(List<Long> ids) {
		Map<Long, BigDecimal> map = new HashMap<>();
		for (Long id : ids) {
			PropertyGuaranteeRepayment propertyGuaranteeRepayment = getById(id);
			if (propertyGuaranteeRepayment == null) {
				return false;
			} else if (propertyGuaranteeRepayment.getStatus() != null &&
					(propertyGuaranteeRepayment.getStatus() != FormStatusConstant.STASH && propertyGuaranteeRepayment.getStatus() != FormStatusConstant.UNREVIEWED)) {
				return false;
			}
			formWorkflowService.deleteProcessInstance(String.valueOf(id));

		}
		return super.deleteLogic(ids);
    }


	@Override
	public HashMap<String,Object> commit(String id) {
		handleStatus(Long.valueOf(id), FormStatusConstant.FLOW,null);

		//将需要提交的流程变量返回，用于工作流侧
		return new HashMap<String,Object>();
	}

	@Override
	public Boolean finish(String id) {
		return handleStatus(Long.valueOf(id), FormStatusConstant.FINISH,"审批通过");
	}

	@Override
	public Boolean reject(String id, int formState, String comment) {
		return handleStatus(Long.valueOf(id), formState,null);
	}

	@Override
	public void cancel(Long id) {
		PropertyGuaranteeRepayment propertyGuaranteeRepayment = getById(id);
		if (Optional.ofNullable(propertyGuaranteeRepayment.getIsAdd()).isPresent() && propertyGuaranteeRepayment.getIsAdd() == 2){
			//还款后增加剩余担保金额
			PropertyGuaranteeApply propertyGuaranteeApply = propertyGuaranteeApplyService.getById(propertyGuaranteeRepayment.getApplyId());
			//剩余担保金额+旧数据
			propertyGuaranteeApply.setGuaranteeRemain(BigDecimalUtil.subtract(propertyGuaranteeApply.getGuaranteeRemain(), propertyGuaranteeRepayment.getReductionGuaranteeAmount()));
			propertyGuaranteeApplyService.updateById(propertyGuaranteeApply);
		}

		List<PropertyGuaranteeRepayment> propertyGuaranteeRepayments = list(new LambdaQueryWrapper<PropertyGuaranteeRepayment>()
				.eq(PropertyGuaranteeRepayment::getExecuteId, propertyGuaranteeRepayment.getExecuteId())
				.eq(PropertyGuaranteeRepayment::getStatus, FormStatusConstant.FINISH)
				.ne(PropertyGuaranteeRepayment::getId, id));
		if(CollectionUtil.isNotEmpty(propertyGuaranteeRepayments)){
			BigDecimal totalRepaymentAmount = propertyGuaranteeRepayments.stream().map(PropertyGuaranteeRepayment::getRepaymentAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
			if (totalRepaymentAmount.compareTo(propertyGuaranteeRepayments.get(0).getLoanAmount()) == -1){
				PropertyGuaranteeExecute propertyGuaranteeExecute = propertyGuaranteeExecuteService.getById(propertyGuaranteeRepayment.getExecuteId());
				propertyGuaranteeExecute.setIsEnd(1);
				propertyGuaranteeExecute.setGuaranteeActualDate(null);
				propertyGuaranteeExecuteService.updateById(propertyGuaranteeExecute);
			}
		}


	}


	/**
	 * 统一处理状态机事件方法
	 * @param id 主键
	 * @param updateStatus 更新状态
	 * @return boolean
	 */
	private Boolean handleStatus(Long id, int updateStatus,String comment) {
		try {
			PropertyGuaranteeRepayment propertyGuaranteeRepayment = getById(id);
			/**
			 * 设置审批人和审批时间
			 */
			if (updateStatus == FormStatusConstant.FINISH){
				propertyGuaranteeRepayment.setApprovedUser(TokenUtil.getTokenUserId());
				Date now = DateUtil.now();
				propertyGuaranteeRepayment.setApprovedTime(now);


				if (Optional.ofNullable(propertyGuaranteeRepayment.getIsAdd()).isPresent() && propertyGuaranteeRepayment.getIsAdd() == 2){
					//还款后增加剩余担保金额
					PropertyGuaranteeApply propertyGuaranteeApply = propertyGuaranteeApplyService.getById(propertyGuaranteeRepayment.getApplyId());
					//剩余担保金额+旧数据
					propertyGuaranteeApply.setGuaranteeRemain(propertyGuaranteeApply.getGuaranteeRemain().add(propertyGuaranteeRepayment.getReductionGuaranteeAmount()));
					propertyGuaranteeApplyService.updateById(propertyGuaranteeApply);
				}

				List<PropertyGuaranteeRepayment> propertyGuaranteeRepayments = list(new LambdaQueryWrapper<PropertyGuaranteeRepayment>()
						.eq(PropertyGuaranteeRepayment::getExecuteId, propertyGuaranteeRepayment.getExecuteId())
						.eq(PropertyGuaranteeRepayment::getStatus, FormStatusConstant.FINISH));
				if(CollectionUtil.isNotEmpty(propertyGuaranteeRepayments)){
					BigDecimal totalRepaymentAmount = propertyGuaranteeRepayments.stream().map(PropertyGuaranteeRepayment::getRepaymentAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
					if (totalRepaymentAmount.compareTo(propertyGuaranteeRepayments.get(0).getLoanAmount()) >= 0){
						PropertyGuaranteeExecute propertyGuaranteeExecute = propertyGuaranteeExecuteService.getById(propertyGuaranteeRepayment.getExecuteId());
						propertyGuaranteeExecute.setIsEnd(2);
						propertyGuaranteeExecute.setGuaranteeActualDate(propertyGuaranteeRepayment.getRepaymentTime());
						propertyGuaranteeExecuteService.updateById(propertyGuaranteeExecute);
					}
				}
			}

			if (StringUtil.isNotBlank(propertyGuaranteeRepayment.getDataSource()) &&
					StringUtil.isNotBlank(propertyGuaranteeRepayment.getDataSourceId())){
				if (updateStatus == FormStatusConstant.FINISH || updateStatus == FormStatusConstant.REJECT){
					ApprovalMessage approvalMessage = new ApprovalMessage();
					approvalMessage.setDataSourceId(propertyGuaranteeRepayment.getDataSourceId());
					approvalMessage.setOpinion(comment);
					approvalMessage.setIsApprove(updateStatus == FormStatusConstant.FINISH ? 2 : 1);
					approvalMessage.setIsSend(1);
					approvalMessage.setDataSourceType(GZW_TYPE);

					if (propertyGuaranteeRepayment.getDataSource().equals(YthConstant.DATA_NINGBO)) {
						approvalMessage.setDataSourceType(YthConstant.DATA_NINGBO);
						approvalMessage.setFilingUserName(UserCache.userIdToName(TokenUtil.getTokenUserId()));
						approvalMessage.setFormType(FormTypeConstant.QM_LISTED_MAJOR_EVENT);
						approvalMessage.setFilingCode(propertyGuaranteeRepayment.getCode());
					}
					approvalMessageService.save(approvalMessage);
				}
			}
			propertyGuaranteeRepayment.setStatus(updateStatus);
			updateById(propertyGuaranteeRepayment);
			return true;
		} catch (Exception e) {
			log.error(ExceptionUtils.getFullStackTrace(e));
			return false;
		}
	}

	@Override
	public void goBackToStash(String formId) {
		cancel(Long.valueOf(formId));
		handleStatus(Long.valueOf(formId), UNREVIEWED,null);
	}

	@Override
	public List<PageData> findByIds(List<String> formIds) {
		LambdaQueryWrapper<PropertyGuaranteeRepayment> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.in(PropertyGuaranteeRepayment::getId, Func.toLongList(StringUtils.join(formIds, StringPool.COMMA)));
		List<PropertyGuaranteeRepayment> propertyGuaranteeRepayments = list(queryWrapper);
		List<PropertyGuaranteeRepaymentVO> propertyGuaranteeRepaymentVOS = propertyGuaranteeRepaymentWrapper.entityToVO(propertyGuaranteeRepayments);
		List<PageData> pageDataList = new ArrayList<>();
		try{
			if (CollectionUtil.isNotEmpty(propertyGuaranteeRepaymentVOS)){
				for (PropertyGuaranteeRepaymentVO vo : propertyGuaranteeRepaymentVOS){
					PageData pd = new PageData();
					pd.put("id", vo.getId());
					pd.put("UNITNAME", vo.getApplyName());
					pd.put("APPLICANTNAME", vo.getCreateUserName());
					pd.put("applicantId", vo.getCreateUser());
					pd.put("applyOrganizationId", vo.getApplyNameId());
					pd.put("formType", FormTypeConstant.QG_GUARANTEE_REPAYMENT_FORM);
					pd.put("orgName", vo.getApplyName());
					pageDataList.add(pd);
				}
			}

			return pageDataList;
		} catch (Exception e) {
			log.error(ExceptionUtils.getFullStackTrace(e));
		}
		return pageDataList;
	}

	@Override
	public List<Integer> getFormType() {
		return Arrays.asList(FormTypeConstant.QG_GUARANTEE_REPAYMENT_FORM);
	}

	@Override
	public boolean submit(PropertyGuaranteeRepayment propertyGuaranteeRepayment) {
		boolean result = saveOrUpdate(propertyGuaranteeRepayment);
		return result;
	}

	@Override
	@Transactional(rollbackFor = RuntimeException.class)
	public String saveGuaranteeRepaymentList(String data){
		YthResult ythResult = new YthResult();
		//成功的id集合
		List<String> successIds = new ArrayList<>();
		//失败的id集合
		List<String> failIds = new ArrayList<>();
		//失败的原因
		List<String> failReasons = new ArrayList<>();
		//将json字符串转换成list
		List<PropertyGuaranteeRepayment> dataList = JSON.parseArray(data, PropertyGuaranteeRepayment.class);
		if (CollectionUtil.isNotEmpty(dataList)){
			Map<String, String> orgSource = orgService.getSourceId();
			//根据datasourceIds 查询出所有的数据
			List<PropertyGuaranteeRepayment> list = list(new LambdaQueryWrapper<PropertyGuaranteeRepayment>().in(PropertyGuaranteeRepayment::getDataSourceId, dataList.stream().map(PropertyGuaranteeRepayment::getDataSourceId).toArray()));
			//如果数据库中有数据，就更新，没有就新增
			for (PropertyGuaranteeRepayment entity:dataList){
				entity.setCode(formCodeService.getCode(FormTypeConstant.QG_GUARANTEE_REPAYMENT_FORM));
				entity.setFormType(String.valueOf(FormTypeConstant.QG_GUARANTEE_REPAYMENT_FORM));
				//id重复略过
				transfer(entity,orgSource);
				if (CollectionUtil.isNotEmpty(list)){
					List<String> olIds = list.stream().map(PropertyGuaranteeRepayment::getDataSourceId).collect(Collectors.toList());
					String dataSourceId = entity.getDataSourceId();
					//判断数据库中是否有数据
					if (olIds.contains(dataSourceId)){
						for (PropertyGuaranteeRepayment oldEntity:list){
							if (dataSourceId.equals(oldEntity.getDataSourceId())){
								//判断status是否为0，如果是0，就更新，不是0，就不更新
								if (CheckStatus.checkCode(oldEntity.getStatus())){
									successIds.add(dataSourceId);
									entity.setId(oldEntity.getId());
									entity.setDataSource(YthConstant.DATA_NINGBO);
									submit(entity);
									list.remove(oldEntity);
									break;
								}else {
									failIds.add(dataSourceId);
									failReasons.add("dataSourceId:"+dataSourceId+"数据已提交且已经在流程中，无法更新");
									break;
								}
							}
						}
					}else {
						//如果数据库中没有数据，就新增
						entity.setDataSource(YthConstant.DATA_NINGBO);
						submit(entity);
						successIds.add(entity.getDataSourceId());
					}
				}else {
					//如果数据库中没有数据，就新增
					entity.setDataSource(YthConstant.DATA_NINGBO);
					submit(entity);
					successIds.add(entity.getDataSourceId());
				}
			}
		} else {
			failReasons.add("数据为空");
		}
		ythResult.setSuccessIds(successIds);
		ythResult.setFailIds(failIds);
		ythResult.setFailReason(StringUtils.join(failReasons, ";"));
		//ythResult转换成json字符串
		return JSON.toJSONString(ythResult);
	}

	private void transfer(PropertyGuaranteeRepayment entity, Map<String, String> orgSourceMap){
		Optional.ofNullable(entity.getExecuteId()).ifPresent(executeId ->
				{
					PropertyGuaranteeExecute guaranteeExecute = propertyGuaranteeExecuteService.getOne(new LambdaQueryWrapper<PropertyGuaranteeExecute>().eq(PropertyGuaranteeExecute::getDataSourceId,executeId));
					Optional.ofNullable(guaranteeExecute).ifPresent(execute ->{
						entity.setExecuteCode(execute.getCode());
						entity.setLoanStartDate(execute.getLoanStartDate());
						entity.setLoanEndDate(execute.getLoanEndDate());
						entity.setLoanLimit(execute.getLoanLimit());
						entity.setLoanNatureId(execute.getLoanNatureId());
						entity.setApplyNameId(execute.getApplyNameId());
						entity.setCreateCompanyId(execute.getApplyNameId());//execute.getUpstreamCodeId()
						PropertyGuaranteeApply guaranteeApply = propertyGuaranteeApplyService.getOne(new LambdaQueryWrapper<PropertyGuaranteeApply>().eq(PropertyGuaranteeApply::getDataSourceId,execute.getUpstreamCodeId()));
						Optional.ofNullable(guaranteeApply).ifPresent(apply ->{
							entity.setApplyId(apply.getId());
							entity.setApprovalNumber(apply.getAskDocNumber());
						});
					});
				}
		);
	}


}
